<?php

namespace DataCube\DataCubeAggregation\Functions\OLAP;

class WindowFunc
{

    // 计算移动平均值
    public static function movingAverage($data, $windowSize)
    {
        $result = [];
        $windowSum = 0;
        $windowCount = 0;

        foreach ($data as $value) {
            $windowSum += $value;
            $windowCount++;

            if ($windowCount >= $windowSize) {
                $result[] = $windowSum / $windowCount;
                $windowSum -= array_shift($data);
                $windowCount--;
            }
        }

        return $result;
    }

    // 计算移动总和
    public static function movingSum($data, $windowSize)
    {
        $result = [];
        $windowSum = 0;
        $windowCount = 0;

        foreach ($data as $value) {
            $windowSum += $value;
            $windowCount++;

            if ($windowCount >= $windowSize) {
                $result[] = $windowSum;
                $windowSum -= array_shift($data);
                $windowCount--;
            }
        }

        return $result;
    }

    // 计算移动最小值
    public static function movingMin($data, $windowSize)
    {
        $result = [];
        $windowValues = [];
        $windowCount = 0;

        foreach ($data as $value) {
            $windowValues[] = $value;
            $windowCount++;

            if ($windowCount >= $windowSize) {
                $result[] = min($windowValues);
                array_shift($windowValues);
                $windowCount--;
            }
        }

        return $result;
    }

    // 计算移动最大值
    public static function movingMax($data, $windowSize)
    {
        $result = [];
        $windowValues = [];
        $windowCount = 0;

        foreach ($data as $value) {
            $windowValues[] = $value;
            $windowCount++;

            if ($windowCount >= $windowSize) {
                $result[] = max($windowValues);
                array_shift($windowValues);
                $windowCount--;
            }
        }

        return $result;
    }
    // 计算排名
    public static function rank($data) {
        $result = [];
        $rankedData = [];
        $rank = 1;

        foreach ($data as $value) {
            if (!in_array($value, $rankedData)) {
                $rankedData[] = $value;
                $result[] = $rank;
                $rank++;
            } else {
                $result[] = $rank;
            }
        }

        return $result;
    }

    // 计算密集排名
    public static function denseRank($data) {
        $result = [];
        $rankedData = [];
        $rank = 1;

        foreach ($data as $value) {
            if (!in_array($value, $rankedData)) {
                $rankedData[] = $value;
                $result[] = $rank;
                $rank++;
            } else {
                $result[] = $rank;
            }
        }

        return $result;
    }

    // 计算行号
    public static function rowNumber($data) {
        $result = [];
        $count = 1;

        foreach ($data as $value) {
            $result[] = $count;
            $count++;
        }

        return $result;
    }

    // 分组编号
    public static function ntile($data, $numGroups) {
        $result = [];
        $groupSize = count($data) / $numGroups;
        $groupCount = 1;
        $groupIndex = 0;

        foreach ($data as $value) {
            if ($groupIndex == 0) {
                $result[] = $groupCount;
                $groupCount++;
            }

            $groupIndex++;
            if ($groupIndex == $groupSize && $groupCount <= $numGroups) {
                $groupIndex = 0;
            } elseif ($groupCount > $numGroups) {
                $groupIndex--;
            }
        }

        return $result;
    }

    // 返回当前行之前的指定列的值
    public static function lag($data, $offset, $defaultValue = null) {
        $result = [];
        $count = count($data);
        $lagValue = $defaultValue;

        for ($i = 0; $i < $count; $i++) {
            if ($i - $offset >= 0) {
                $lagValue = $data[$i - $offset];
            } else {
                $lagValue = $defaultValue;
            }
            $result[] = $lagValue;
        }

        return $result;
    }

    // 返回当前行之后的指定列的值
    public static function lead($data, $offset, $defaultValue = null) {
        $result = [];
        $count = count($data);
        $leadValue = $defaultValue;
        $endIndex = $count - 1; // 最后一个元素的索引
        for ($i = 0; $i <= $endIndex; $i++) { // 遍历到最后一个元素，以便获取最后一个元素的lead值
            if ($i + $offset <= $endIndex) { // 确保索引不超出范围
                $leadValue = $data[$i + $offset];
            } else {
                $leadValue = $defaultValue;
            }
            if ($i == 0) {
                for ($j = 0; $j < $offset; $j++) {
                    array_unshift($result, $defaultValue); // 在结果数组开头插入默认值，以保证结果数组长度与输入数组一致
                }
            }
            $result[] = $leadValue;
        }
        return $result;
    }

    // 返回窗口中的第一行的指定列的值
    public static function firstValue($data) {
        return [reset($data)];
    }

    // 返回窗口中的最后一行的指定列的值
    public static function lastValue($data) {
        return [end($data)];
    }

    public function nth_value($array, $n, $orderBy = null) {
        if (!is_array($array) || !isset($array[$n])) {
            return null;
        }

        if ($orderBy !== null) {
            // 根据排序规则对数组进行排序
            uasort($array, function($a, $b) use ($orderBy) {
                foreach ($orderBy as $column => $direction) {
                    $valueA = is_array($a) ? $a[$column] : $a;
                    $valueB = is_array($b) ? $b[$column] : $b;

                    if ($direction === 'ASC') {
                        if ($valueA < $valueB) {
                            return -1;
                        } elseif ($valueA > $valueB) {
                            return 1;
                        }
                    } elseif ($direction === 'DESC') {
                        if ($valueA > $valueB) {
                            return -1;
                        } elseif ($valueA < $valueB) {
                            return 1;
                        }
                    }
                }

                return 0;
            });
        }

        return $array[$n];
    }
}
